﻿using System.Collections.Generic;
using System.Linq;
using Rocuna.Core.Exceptions;

namespace Rocuna.Log
{
    /// <summary>
    /// Manager for logging tasks.
    /// </summary>
    public class LogManager
    {
        #region Constructor

        protected LogManager()
        {
            _defaultLogger = null;
            _loggersList = new Dictionary<string, Logger>();
            CreateLogger("Default");
        }

        #endregion

        #region Singleton Implementation

        private static LogManager _instance;

        /// <summary>
        /// Gets the singleton instance.
        /// </summary>
        public static LogManager Instance
        {
            get
            {
                if (_instance == null)
                    throw new NotStartedException(typeof(LogManager));
                return _instance;
            }
        }

        #endregion

        #region Properties And fields

        private readonly Dictionary<string, Logger> _loggersList;

        private Logger _defaultLogger;

        /// <summary>
        /// Gets the default logger.
        /// </summary>
        public Logger DefaultLogger { get { return _defaultLogger; } }

        #endregion

        #region Creation and set methods

        /// <summary>
        /// Creates the logger.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="defaultLogger">if set to <c>true</c> [default logger].</param>
        /// <param name="debuggerOutput">if set to <c>true</c> [debugger output].</param>
        /// <returns>The created logger</returns>
        public Logger CreateLogger(string name, bool defaultLogger = false, bool debuggerOutput = true)
        {
            var logger = new Logger(name, debuggerOutput);
            if (_defaultLogger == null || defaultLogger)
                _defaultLogger = logger;
            _loggersList.Add(name, logger);
            return logger;
        }

        /// <summary>
        /// Sets the default logger.
        /// </summary>
        /// <param name="newLogger">The new logger.</param>
        /// <returns>the last default Logger</returns>
        public Logger SetDefaultLogger(Logger newLogger)
        {
            var oldLogger = _defaultLogger;
            _defaultLogger = newLogger;
            return oldLogger;
        }

        /// <summary>
        /// Removes the logger.
        /// </summary>
        /// <param name="name">The name.</param>
        public void RemoveLogger(string name)
        {
            if (_loggersList.ContainsKey(name))
            {
                var logger = _loggersList[name];
                if (_defaultLogger == logger)
                {
                    _defaultLogger = null;
                }
                _loggersList.Remove(name);
            }
            //Assign new default logger if needed.
            if (_defaultLogger == null && _loggersList.Count > 0)
            {
                _defaultLogger = _loggersList.First().Value;
            }
        }

        /// <summary>
        /// Removes the logger.
        /// </summary>
        /// <param name="logger">The logger.</param>
        public void RemoveLogger(Logger logger)
        {
            RemoveLogger(logger.Name);
        }

        /// <summary>
        /// Debugs the specified MSG.
        /// </summary>
        /// <param name="msg">The MSG.</param>
        /// <param name="maskDebug">if set to <c>true</c> [mask debug].</param>
        public void Debug(string msg, bool maskDebug = false)
        {
            if (_defaultLogger != null)
                _defaultLogger.LogMessage(msg, LogLevel.Debug, maskDebug);
        }

        /// <summary>
        /// Warns the specified MSG.
        /// </summary>
        /// <param name="msg">The MSG.</param>
        /// <param name="maskDebug">if set to <c>true</c> [mask debug].</param>
        public void Warn(string msg, bool maskDebug = false)
        {
            if (_defaultLogger != null)
                _defaultLogger.LogMessage(msg, LogLevel.Warning, maskDebug);
        }

        /// <summary>
        /// Errors the specified MSG.
        /// </summary>
        /// <param name="msg">The MSG.</param>
        /// <param name="maskDebug">if set to <c>true</c> [mask debug].</param>
        public void Error(string msg, bool maskDebug = false)
        {
            if (_defaultLogger != null)
                _defaultLogger.LogMessage(msg, LogLevel.Error, maskDebug);
        }

        /// <summary>
        /// Sets the logger level.
        /// </summary>
        /// <param name="logLevel">The log level.</param>
        public void SetLoggerLevel(LogDetailsLevel logLevel)
        {
            if (_defaultLogger != null)
                _defaultLogger.LoggerLevel = logLevel;
        }

        #endregion

        #region Indexers

        /// <summary>
        /// Gets the <see cref="Rocuna.Log.Logger"/> with the specified name.
        /// </summary>
        public Logger this[string name]
        {
            get { return _loggersList[name]; }
        }

        #endregion

        #region Static Start engine method

        /// <summary>
        /// Starts the engine.
        /// </summary>
        public static void StartEngine()
        {
            _instance = new LogManager();
        }

        #endregion
    }
}